/** storage 存储类 */
export class Storage {
	options = {
		sync: true,
		expires: Infinity,
		prefix: '',
		includeExpired: false,
	}

	constructor(opts = {}) {
		this.options = Object.assign({}, this.options, opts)
	}

	/**
	 * 从 uni.Storage 获取值
	 *
	 * 如果值已经过期, 则返回空字符串
	 *
	 * @param options.sync 是否同步获取
	 * @param options.includeExpired 如果为 `true` 则, 过期也可获取内容
	 */
	// get(key, options? )
	// async get(key, options ? )
	get(
		key,
		options = {},
	) {
		const opts = Object.assign({}, this.options, options)
		if (opts.prefix) key = `${opts.prefix}${key}`
		let value
		if (opts.sync) {
			// 同步
			value = uni.getStorageSync(key)
			return value.expiredAt ? (+value.expiredAt < Date.now() ? '' : value.data) : value.data
		} else {
			// 异步
			return new Promise((resolve, reject) => {
				uni.getStorage({
					key,
					success: (res) => {
						value = res.data
						if (+value.expiredAt < Date.now()) return resolve('')
						else return resolve(value.data)
					},
					fail: (err) => reject(err),
				})
			})
		}
	}

	/**
	 * 向 uni.Storage 存储值
	 *
	 * @param options.sync 是否同步存储
	 * @param options.expires 有效期, 单位分钟, 默认永不过期
	 */
	set(
		key,
		data,
		options = {},
	) {
		const opts = Object.assign({}, this.options, options)
		if (opts.prefix) key = `${opts.prefix}${key}`
		const value = {
			data,
			expiredAt: new Date(Date.now() + opts.expires * 60000),
		}
		if (opts.sync) return void uni.setStorageSync(key, value)
		return new Promise((resolve, reject) => {
			uni.setStorage({
				key,
				data: value,
				success: (res) => resolve(res),
				fail: (err) => reject(err),
			})
		})
	}

	/**
	 * 判断某个值是否过期, 如果不存在则返回 null
	 */
	isExpired(key) {
		const value = this.get(key, {
			includeExpired: true,
			sync: true
		})
		if (!value) return null
		return !this.get(key, {
			includeExpired: false,
			sync: true
		})
	}

	/** 从 storage 移除某值 */
	remove(key, options = {}) {
		const opts = Object.assign({}, this.options, options)
		if (opts.prefix) key = `${opts.prefix}${key}`
		uni.removeStorageSync(key)
	}

	/**
	 * 清空 storage
	 *
	 * @param options.sync 是否同步清除
	 */
	clear(options = {}) {
		const opts = Object.assign({}, this.options, options)
		if (opts.sync) uni.clearStorageSync()
		else uni.clearStorage()
	}
}
